using System.Buffers;
using Google.Protobuf;
using Google.Protobuf.Reflection;
using SuperSocket.ProtoBase;

namespace Core;

/// <summary>
/// | bodyLength | body |
/// | header | cmd | body |
/// </summary>
public sealed class PlayPipeLineFilter : FixedHeaderPipelineFilter<BaseCommand>
{
    private static readonly MessageParser[] MessageFactorys;

    static PlayPipeLineFilter()
    {
        var messageTypes = GeneratedCodeReflection.Descriptor.MessageTypes.ToDictionary(key => key.ClrType, value => value.Parser);

        MessageFactorys = new MessageParser[messageTypes.Count];

        foreach (var messageType in messageTypes)
        {
            var command = messageType.Key.GetCustomAttributes(true)
                .OfType<CommandKeyAttribute>()
                .FirstOrDefault();

            if (command == null)
                continue;

            MessageFactorys[(int)command.Key] = messageType.Value;
        }
    }

    private const byte HeaderLength = 2;

    public PlayPipeLineFilter()
        : base(HeaderLength)
    {
    }

    protected override BaseCommand DecodePackage(ref ReadOnlySequence<byte> buffer)
    {
        var reader = new SequenceReader<byte>(buffer.Slice(HeaderLength));

        if (!reader.TryRead(out var cmd))
            throw new ProtocolException($"读取命令错误{cmd}");

        var factory = MessageFactorys[cmd];

        var command = (BaseCommand)factory.ParseFrom(reader.UnreadSequence);

        command.Key = (CommandType)cmd;

        return command;
        
        //子类=>父类>子类>父类
    }

    protected override int GetBodyLengthFromHeader(ref ReadOnlySequence<byte> buffer)
    {
        var reader = new SequenceReader<byte>(buffer);

        reader.TryReadLittleEndian(out short bodyLength);

        return bodyLength;
    }
}

